package com.flyxteam.commons.crypto;

import java.security.InvalidKeyException;
import java.security.Key;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;

import com.flyxteam.commons.base.util.Base64Util;


/**
 * <b>功能：</b>RSA工具类. 注意, 被加密的bytes长度需要小于等于117<br>
 * <b>说明：</b><br>
 * 1.使用{@link #genKeys()}生成公钥, 私钥.<br>
 * 2.使用{@link #encryptByPrivateKey(byte[], byte[])}等加密方法加密.<br>
 * 3.使用{@link #decryptByPublicKey(byte[], byte[])}等解密方法解密.<br>
 * <ul>
 * <li>2017-01-01 | ChrisX | + create</li>
 * </ul>
 * @author ChrisX
 */
public class RSAUtil {
    
    private RSAUtil() {}
	
	/** 算法名称 */
	public static final String KEY_ALGORITHM = "RSA";
	
	//public static final String SIGNATURE_ALGORITHM = "MD5withRSA";

	/**
	 * <b>功能描述：</b>生成密钥对.<br>
	 * @return [公钥, 私钥]
	 * @throws RuntimeException 封装NoSuchAlgorithmException
	 */
	public static byte[][] genKeys() {
		KeyPairGenerator keyPairGen;
		try {
			keyPairGen = KeyPairGenerator.getInstance(KEY_ALGORITHM);
		} catch (NoSuchAlgorithmException e) {
			throw new RuntimeException(e);//应该不会
		}
		keyPairGen.initialize(1024);
		KeyPair keyPair = keyPairGen.generateKeyPair();
		// 公钥
		RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
		// 私钥
		RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();
		return new byte[][]{publicKey.getEncoded(), privateKey.getEncoded()};
	}
	
	//------------------------ 加密
	
	/**
	 * {@link #encryptByPublicKey(byte[], byte[])}, key是base64字符串.
	 */
	public static byte[] encryptByPublicKey(byte[] data, String publicKey) {
		// 对公钥解密
		byte[] keyBytes = Base64Util.decode(publicKey);
		return encryptByPublicKey(data, keyBytes);
	}
	
	/**
	 * <b>功能描述：</b>用公钥加密<br>
	 * @param data 被加密
	 * @param publicKey 公钥
	 * @throws RuntimeException 对各种加密异常的封装
	 */
	public static byte[] encryptByPublicKey(byte[] data, byte[] publicKey) {
		// 取得公钥
		X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(publicKey);
		KeyFactory keyFactory;
		try {
			keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
		} catch (NoSuchAlgorithmException e) {
			throw new RuntimeException(e);//应该不会
		}
		Key publicKeyObject;
		try {
			publicKeyObject = keyFactory.generatePublic(x509KeySpec);
		} catch (InvalidKeySpecException e) {
			throw new RuntimeException(e);//应该不会, 除非key不标准
		}
		// 对数据加密
		Cipher cipher;
		try {
			cipher = Cipher.getInstance(keyFactory.getAlgorithm());
		} catch (NoSuchAlgorithmException e) {
			throw new RuntimeException(e);//应该不会
		} catch (NoSuchPaddingException e) {
			throw new RuntimeException(e);//应该不会
		}
		try {
			cipher.init(Cipher.ENCRYPT_MODE, publicKeyObject);
		} catch (InvalidKeyException e) {
			throw new RuntimeException(e);//应该不会, 除非key不标准
		}
		try {
			return cipher.doFinal(data);
		} catch (IllegalBlockSizeException e) {
			throw new RuntimeException(e);//应该不会
		} catch (BadPaddingException e) {
			throw new RuntimeException(e);//应该不会
		}
	}

	/**
	 * {@link #encryptByPrivateKey(byte[], byte[])}, key是base64字符串.
	 */
	public static byte[] encryptByPrivateKey(byte[] data, String key) {
		byte[] keyBytes = Base64Util.decode(key);
		return encryptByPrivateKey(data, keyBytes);
	}
	
	/**
	 * <b>功能描述：</b>用私钥加密.<br>
	 * @param data 被加密
	 * @param privateKey 私钥
	 * @throws RuntimeException 对各种加密异常的封装
	 */
	public static byte[] encryptByPrivateKey(byte[] data, byte[] privateKey) {
		// 取得私钥
		try{
			PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(privateKey);
			KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
			Key privateKeyObject = keyFactory.generatePrivate(pkcs8KeySpec);
			// 对数据加密
			Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
			cipher.init(Cipher.ENCRYPT_MODE, privateKeyObject);
			
			return cipher.doFinal(data);
		} catch (InvalidKeyException e){
			throw new RuntimeException(e);
		} catch (NoSuchAlgorithmException e) {
			throw new RuntimeException(e);
		} catch (InvalidKeySpecException e) {
			throw new RuntimeException(e);
		} catch (NoSuchPaddingException e) {
			throw new RuntimeException(e);
		} catch (IllegalBlockSizeException e) {
			throw new RuntimeException(e);
		} catch (BadPaddingException e) {
			throw new RuntimeException(e);
		}
	}
	
	//---------------------- 解密

	/**
	 * {@link #decryptByPrivateKey(byte[], byte[])}, key是base64字符串.
	 */
	public static byte[] decryptByPrivateKey(byte[] data, String key) {
		byte[] keyBytes = Base64Util.decode(key);
		return decryptByPrivateKey(data, keyBytes);
	}
	
	/**
	 * <b>功能描述：</b>用私钥解密<br>
	 * @param data 密文
	 * @param privateKey 私钥
	 * @throws RuntimeException 对各种加密异常的封装
	 */
	public static byte[] decryptByPrivateKey(byte[] data, byte[] privateKey) {
		try{
			// 取得私钥
			PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(privateKey);
			KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
			Key privateKeyObject = keyFactory.generatePrivate(pkcs8KeySpec);
			// 对数据解密
			Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
			cipher.init(Cipher.DECRYPT_MODE, privateKeyObject);
			return cipher.doFinal(data);
		} catch (InvalidKeyException e){
			throw new RuntimeException(e);
		} catch (NoSuchAlgorithmException e) {
			throw new RuntimeException(e);
		} catch (InvalidKeySpecException e) {
			throw new RuntimeException(e);
		} catch (NoSuchPaddingException e) {
			throw new RuntimeException(e);
		} catch (IllegalBlockSizeException e) {
			throw new RuntimeException(e);
		} catch (BadPaddingException e) {
			throw new RuntimeException(e);
		}
	}

	/**
	 * {@link #decryptByPublicKey(byte[], byte[])}, key是base64字符串.
	 */
	public static byte[] decryptByPublicKey(byte[] data, String key) {
		byte[] keyBytes = Base64Util.decode(key);
		return decryptByPublicKey(data, keyBytes);
	}
	
	/**
	 * <b>功能描述：</b>用公钥解密.<br>
	 * @param data 密文
	 * @param publicKey 公钥
	 * @throws RuntimeException 对各种加密异常的封装
	 */
	public static byte[] decryptByPublicKey(byte[] data, byte[] publicKey) {
		// 取得公钥
		try{
			X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(publicKey);
			KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
			Key publicKeyObject = keyFactory.generatePublic(x509KeySpec);
			// 对数据解密
			Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
			cipher.init(Cipher.DECRYPT_MODE, publicKeyObject);
			return cipher.doFinal(data);
		} catch (InvalidKeyException e){
			throw new RuntimeException(e);
		} catch (NoSuchAlgorithmException e) {
			throw new RuntimeException(e);
		} catch (InvalidKeySpecException e) {
			throw new RuntimeException(e);
		} catch (NoSuchPaddingException e) {
			throw new RuntimeException(e);
		} catch (IllegalBlockSizeException e) {
			throw new RuntimeException(e);
		} catch (BadPaddingException e) {
			throw new RuntimeException(e);
		}
	}
	
}
